package com.csun.cmny.provider.controller.admin;

import com.csun.cmny.base.constant.GlobalConstant;
import com.csun.cmny.base.enums.ErrorCodeEnum;
import com.csun.cmny.config.properties.CmnyProperties;
import com.csun.cmny.core.utils.MD5Util;
import com.csun.cmny.provider.dao.DmcCsunVersionSetDeviceMapper;
import com.csun.cmny.provider.device.card.CardMessageHandler;
import com.csun.cmny.provider.device.csun.camera.CameraMessageHandler;
import com.csun.cmny.provider.device.csun.camera.entity.CsunCameraData;
import com.csun.cmny.provider.device.csun.camera.entity.CsunCameraPictureAckMsg;
import com.csun.cmny.provider.device.relay.RelayMessageHandler;
import com.csun.cmny.provider.device.relay.entity.RelayCmdStachEntity;
import com.csun.cmny.provider.exceptions.DmcBizException;
import com.csun.cmny.provider.exceptions.OmcBizException;
import com.csun.cmny.provider.model.constant.CameraConstant;
import com.csun.cmny.provider.model.constant.DeviceConstant;
import com.csun.cmny.provider.model.constant.LifeConstant;
import com.csun.cmny.provider.model.domain.*;
import com.csun.cmny.provider.model.dto.attachment.OptUploadFileByteInfoReqDto;
import com.csun.cmny.provider.model.dto.oss.OptUploadFileReqDto;
import com.csun.cmny.provider.model.dto.oss.OptUploadFileRespDto;
import com.csun.cmny.provider.model.dto.relay.RelayAuthDto;
import com.csun.cmny.provider.model.dto.rfid.RfidReaderDto;
import com.csun.cmny.provider.model.dto.rfid.RfidReaderGroupDto;
import com.csun.cmny.provider.model.dto.version.CsunVersionQueryDto;
import com.csun.cmny.provider.model.dto.version.PacketVersionDto;
import com.csun.cmny.provider.model.vo.AlarmLightVo;
import com.csun.cmny.provider.model.vo.OldmanBedRoomBuildingVo;
import com.csun.cmny.provider.model.vo.card.ControllerCardVo;
import com.csun.cmny.provider.model.vo.csunversion.CsunVersionFileVo;
import com.csun.cmny.provider.model.vo.csunversion.CsunVersionPackVo;
import com.csun.cmny.provider.model.vo.csunversion.CsunVersionVo;
import com.csun.cmny.provider.model.vo.nursing.NursingGroupOldmanVo;
import com.csun.cmny.provider.model.vo.rfid.DmcRfidEventOldmanVo;
import com.csun.cmny.provider.model.vo.rfid.DmcRfidLabelVo;
import com.csun.cmny.provider.model.vo.rfid.DmcRfidReaderVo;
import com.csun.cmny.provider.resolver.CmnyMessageSource;
import com.csun.cmny.provider.service.*;
import com.csun.cmny.provider.service.impl.JPushService;
import com.csun.cmny.util.DateUtil;
import com.csun.cmny.util.PublicUtil;
import com.csun.cmny.util.RedisKeyUtil;
import com.csun.cmny.util.wrapper.WrapMapper;
import com.csun.cmny.util.wrapper.Wrapper;
import com.google.common.base.Preconditions;
import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
import io.swagger.annotations.Api;
import lombok.extern.slf4j.Slf4j;
import net.sf.json.JSONObject;
import org.apache.commons.codec.binary.Base64;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.core.io.ClassPathResource;
import org.springframework.core.io.FileSystemResource;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.http.HttpEntity;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpMethod;
import org.springframework.http.MediaType;
import org.springframework.util.LinkedMultiValueMap;
import org.springframework.util.MultiValueMap;
import org.springframework.util.StringUtils;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.client.RestTemplate;
import org.springframework.web.multipart.MultipartFile;
import org.springframework.web.multipart.MultipartHttpServletRequest;
import sun.misc.BASE64Decoder;
import sun.misc.BASE64Encoder;

import javax.annotation.Resource;
import javax.imageio.ImageIO;
import javax.servlet.ServletOutputStream;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.awt.image.BufferedImage;
import java.io.*;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.Map;
import java.util.concurrent.TimeUnit;

/**
 * @Auther: chisj chisj@foxmal.com
 * @Date: 2019-01-22 14:59
 * @Description: the class auth rest controller
 */
@Slf4j
@RestController
@RequestMapping(value = "/auth")
@Api(value = "Web-AuthRestController", produces = MediaType.APPLICATION_JSON_UTF8_VALUE)
public class AuthRestController {

    @Resource
    private RedisTemplate<String, Object> redisTemplate;
    @Resource
    private CmnyMessageSource cmnyMessageSource;
    @Resource
    private DmcWatchAlarmClockService dmcWatchAlarmClockService;
    @Resource
    private DmcRfidEventService dmcRfidEventService;
    @Resource
    private DmcRfidEventOldmanService dmcRfidEventOldmanService;
    @Resource
    private DmcRfidLabelOldmanService dmcRfidLabelOldmanService;
    @Resource
    private DmcRfidReaderLocationService dmcRfidReaderLocationService;
    @Resource
    private DmcRfidReaderGroupService dmcRfidReaderGroupService;
    @Resource
    private OmcRpcService omcRpcService;
    @Resource
    private DmcDeviceAlertService dmcDeviceAlertService;
    @Resource
    private DmcAlarmLightLocationService dmcAlarmLightLocationService;
    @Resource
    private DmcRelayAuthDeviceService dmcRelayAuthDeviceService;
    @Resource
    private DmcServerService dmcServerService;
    @Resource
    private JPushService jPushService;
    @Resource
    private OpcRpcService opcRpcService;
    @Resource
    private DmcControllerCardBindService dmcControllerCardBindService;
    @Resource
    private CardMessageHandler cardMessageHandler;
    @Resource
    private CmnyProperties cmnyProperties;
    @Resource
    private DmcRfidReaderGroupBindService dmcRfidReaderGroupBindService;
    @Resource
    private DmcCsunCameraPictureService dmcCsunCameraPictureService;
    @Resource
    private RelayMessageHandler relayMessageHandler;
    @Resource
    private CameraMessageHandler cameraMessageHandler;
    @Resource
    private DmcCsunVersionFileService dmcCsunVersionFileService;
    @Resource
    private DmcCsunCameraAlertVideoService dmcCsunCameraAlertVideoService;
    @Resource
    private DmcCsunVersionSetDeviceMapper dmcCsunVersionSetDeviceMapper;
    @Resource
    private DmcCsunSleepCollectionService dmcCsunSleepCollectionService;
    @Resource
    private DmcCsunCameraWebRtcService dmcCsunCameraWebRtcService;
    @Autowired
    private RestTemplate myRestTemplate;
    @Resource
    private DmcGuoKangClientService dmcGuoKangClientService;

    @RequestMapping(value = "/batchUpdate", method = RequestMethod.POST)
    public Wrapper batchUpdate() {

        List<DmcCsunVersionSetDevice> dmcCsunVersionSetDeviceList = Lists.newArrayList();
        DmcCsunVersionSetDevice first = new DmcCsunVersionSetDevice();
        first.setVersionSetId(126l);
        first.setDeviceId(1632l);
        first.setTaskId("1234");
        first.setStat(7);
        dmcCsunVersionSetDeviceList.add(first);

        DmcCsunVersionSetDevice second = new DmcCsunVersionSetDevice();
        second.setVersionSetId(126l);
        second.setDeviceId(1646l);
        second.setTaskId("1235");
        second.setStat(7);
        dmcCsunVersionSetDeviceList.add(second);

        dmcCsunVersionSetDeviceMapper.batchUpdate(dmcCsunVersionSetDeviceList);

        return WrapMapper.ok();
    }

    @RequestMapping(value = "/setCsunSleepDataFilePrefix", method = RequestMethod.POST)
    public Wrapper setCsunSleepDataFilePrefix(String filePrefix) {

        redisTemplate.opsForValue().set(RedisKeyUtil.getCsunSleepDataFilePrefix(), filePrefix);

        return WrapMapper.ok();
    }

    @RequestMapping(value = "/getCsunSleepDataFilePrefix", method = RequestMethod.POST)
    public Wrapper getCsunSleepDataFilePrefix() {

        String filePrefix = (String) redisTemplate.opsForValue().get(RedisKeyUtil.getCsunSleepDataFilePrefix());

        return WrapMapper.ok(filePrefix);
    }

    /**
     * 查询App版本
     *
     * @return the wrapper
     */
    @RequestMapping(value = "/queryAppVersion", method = RequestMethod.POST)
    public Wrapper queryAppVersion(@RequestBody CsunVersionQueryDto csunVersionQueryDto) {

        csunVersionQueryDto.setPageNum(1);
        csunVersionQueryDto.setPageSize(1);

        List<CsunVersionFileVo> csunVersionFileVoList = dmcCsunVersionFileService.queryCsunVersionListWithPage(csunVersionQueryDto);

        CsunVersionFileVo result = new CsunVersionFileVo();
        if (PublicUtil.isNotEmpty(csunVersionFileVoList)) {
            result = csunVersionFileVoList.get(0);
        }

        return WrapMapper.wrap(Wrapper.SUCCESS_CODE,
                cmnyMessageSource.getMessage("operation.success", null),
                result);
    }

    /**
     * 门禁卡上传消息
     */
    // @LogAnnotation(isSaveRequestData = true, isSaveResponseData = true)
    @RequestMapping(value = "/rfidLabelUploadMsg", method = RequestMethod.POST)
    public Wrapper rfidLabelUploadMsg(HttpServletRequest request) throws IOException {

        // 门禁读卡器编号
        String readerNo = request.getParameter("readerNo");

        // 门禁卡编号
        InputStream is = request.getInputStream();
        byte[] buffer = new byte[400];
        int i = is.read(buffer);
        byte check = getCheckSum(buffer,15);
        byte sum = buffer[15];
        log.info("rfid label msg check = [{}], sum = [{}]", check, sum);

        // 校验卡号校验和
        if (check != sum) {
            log.error("卡号校验失败.");
        }

        // 门禁卡编号
        String labelNo = bytes2hex(buffer, i);
        log.info("==> rfid msg: {}", labelNo);
        // 去掉包头和包尾就是门禁卡的编号
        labelNo = labelNo.substring(4, 28);
        log.info("==> label no: {}", labelNo);

        // 根据门禁读卡器编号查询门禁读卡器信息
        DmcRfidReaderVo dmcRfidReaderVo = dmcRfidReaderLocationService.selectByRfidReaderNo(readerNo);
        if (dmcRfidReaderVo == null) {  // 判断门禁读卡器是否存在
            // 无门禁读卡器
            throw new DmcBizException(ErrorCodeEnum.DMC10063001);
        }

        if (PublicUtil.isEmpty(dmcRfidReaderVo.getLocation())) { // 判断门禁读卡器是否绑定位置
            throw new DmcBizException(ErrorCodeEnum.DMC10063002);
        }

        // 根据门禁卡编号查询门禁卡信息
        DmcRfidLabelVo dmcRfidLabelVo = dmcRfidLabelOldmanService.selectByRfidLabelNo(labelNo);
        if (dmcRfidLabelVo == null) { // 门禁门禁卡是否存在
            throw new DmcBizException(ErrorCodeEnum.DMC10065001);
        }

        if (dmcRfidLabelVo.getRoleCode() == null) {
            throw new DmcBizException(ErrorCodeEnum.DMC100612007);
        }

        // 判断门禁卡两次刷卡的间隔
        DmcRfidEvent dmcRfidEvent = dmcRfidEventService.selectOneByLabelNo(labelNo);
        if (dmcRfidEvent != null) {
            // 判断上次和本次的间隔时间
            Long now_time = System.currentTimeMillis();
            Long his_time = dmcRfidEvent.getCreatedTime().getTime();
            if (now_time - his_time <= 10 * 1000) {
                throw new DmcBizException(ErrorCodeEnum.DMC10065003);
            }
        }

        // 保存门禁事件
        dmcRfidEvent = new DmcRfidEvent();
        dmcRfidEvent.setOldmanId(dmcRfidLabelVo.getOldmanId());
        dmcRfidEvent.setOldmanName(dmcRfidLabelVo.getOldmanName());
        dmcRfidEvent.setRoleId(dmcRfidLabelVo.getRoleId());
        dmcRfidEvent.setRoleCode(dmcRfidLabelVo.getRoleCode());
        dmcRfidEvent.setRoleName(dmcRfidLabelVo.getRoleName());
        dmcRfidEvent.setLocation(dmcRfidReaderVo.getLocation());
        dmcRfidEvent.setGroupId(dmcRfidLabelVo.getGroupId());
        dmcRfidEvent.setLabelId(dmcRfidLabelVo.getId());
        dmcRfidEvent.setLabelNo(dmcRfidLabelVo.getDeviceNo());
        dmcRfidEvent.setReaderId(dmcRfidReaderVo.getId());
        dmcRfidEvent.setReaderNo(dmcRfidReaderVo.getDeviceNo());
        dmcRfidEventService.save(dmcRfidEvent);

        /**
         * @data    2019-12-09
         * @author  chisj
         * @desc    一对门禁组中, 门禁一的设备是唯一的，门禁二可以出现多个门禁组中
         */
//        DmcRfidReaderGroupBind dmcRfidReaderGroupBind = new DmcRfidReaderGroupBind();
//        dmcRfidReaderGroupBind.setRfidReaderId(dmcRfidReaderVo.getId());
//        int count = dmcRfidReaderGroupBindService.selectCount(dmcRfidReaderGroupBind);

        // 开门流程
        ControllerCardVo controllerCardVo = dmcControllerCardBindService.queryControllerCardByRfidReaderId(dmcRfidReaderVo.getId());
        if (controllerCardVo != null) {
            log.info("====> 绑定的门禁控制卡 deviceNo = {}", controllerCardVo.getDeviceNo());
            // 判断是否可以开门
            if (controllerCardVo.getRfidReaderVoList().get(0).getPermission().equals(1)
                    && dmcRfidLabelVo.getDoor().equals(0)) {
                // 不开门 -- 开门权限 && 不开门
                log.warn("====> 门禁控制卡不开门...");
            } else  {
                byte[] doors = { 0x01, 0x00, 0x00, 0x00};   // 只开门一
                cardMessageHandler.openDoor(controllerCardVo.getDeviceNo(), doors);
            }
        } else {
            log.info("====> 尚未绑定的门禁控制卡...");
        }

        if (dmcRfidLabelVo.getRoleCode().equals(DeviceConstant.RFID_ROLE_CODE_OLDMAN)) {

            if (PublicUtil.isEmpty(dmcRfidLabelVo.getOldmanId())) { // 判断门禁是否绑定老人
                throw new DmcBizException(ErrorCodeEnum.DMC10065002);
            }

            // 查询老人床位房间楼栋信息
            OldmanBedRoomBuildingVo obrvo = omcRpcService
                    .queryOldmanBedRoomBuildingByOldmanId(dmcRfidLabelVo.getOldmanId().intValue());
            if (PublicUtil.isEmpty(obrvo)) {
                throw new DmcBizException(ErrorCodeEnum.DMC10066005);
            }
            dmcRfidLabelVo.setOldmanName(obrvo.getOldmanName());


            // 判断门禁读卡器是否在门禁组
            RfidReaderGroupDto rfidReaderGroupDto = dmcRfidReaderGroupService
                    .selectByRfidReaderId(dmcRfidReaderVo.getId());

            if (rfidReaderGroupDto != null) {   // 判断门禁组是否为空
                // 走门禁组报警流程
                rfidReaderGroupProccess(dmcRfidReaderVo, dmcRfidLabelVo, rfidReaderGroupDto, dmcRfidEvent, obrvo);
                // rfidReaderGroupProccess(dmcRfidReaderVo, dmcRfidLabelVo, null, dmcRfidEvent, obrvo);
            } else {
                // 走门禁报警流程
                /**
                 * @data    2019-12-13
                 * @author  chisj
                 * @desc    单个门禁是否需要报警，根据门禁读卡器配置
                 *
                 *
                 */
                if (dmcRfidReaderVo.getOpen() != null
                        && dmcRfidReaderVo.getOpen().equals(1)) {
                    rfidReaderProcess(dmcRfidReaderVo, dmcRfidLabelVo, obrvo);
                }
            }
        }

        return WrapMapper.ok();
    }

    /**
     * 门禁报警流程
     *
     * @param dmcRfidReaderVo   the dmc rfid reader vo
     * @param dmcRfidLabelVo    the dmc rfid label vo
     */
    public void rfidReaderProcess(DmcRfidReaderVo dmcRfidReaderVo,
                                  DmcRfidLabelVo dmcRfidLabelVo, OldmanBedRoomBuildingVo obrvo) {

        // 判断老人是否限制外出
        String specialCase = omcRpcService.queryOldmanSpecialCaseByOldmanId(dmcRfidLabelVo.getOldmanId().intValue());
        if (PublicUtil.isEmpty(specialCase)) {  // 判断有无特殊说明
            throw new DmcBizException(ErrorCodeEnum.DMC10065004);
        }
        String array[] = specialCase.split("-");
        if (array.length < 1 || !array[0].equals("0")) {
            throw new DmcBizException(ErrorCodeEnum.DMC10065004);
        }

        // 限制老人外出 发送报警
        DmcDeviceAlert dmcDeviceAlert = new DmcDeviceAlert();
        Integer result = dmcDeviceAlertService.rfidReaderAlertMsg(dmcRfidReaderVo.getLocation(),
                dmcRfidLabelVo, dmcDeviceAlert, obrvo);
        if (result > 0) {
            dmcDeviceAlertService.sendDeviceAlertMsg(dmcDeviceAlert, obrvo);
            dmcDeviceAlertService.sendLifeMsg(dmcDeviceAlert, obrvo, LifeConstant.YES_SOUND);
        }
    }

    /**
     * 门禁组报警流程
     *
     * @param dmcRfidReaderVo       the dmc rfid reader vo
     * @param dmcRfidLabelVo        the dmc rfid label vo
     * @param rfidReaderGroupDto    the rfid reader group dto
     * @param dmcRfidEvent          the rfid event
     */
    public void rfidReaderGroupProccess(DmcRfidReaderVo dmcRfidReaderVo,
                                        DmcRfidLabelVo dmcRfidLabelVo,
                                        RfidReaderGroupDto rfidReaderGroupDto,
                                        DmcRfidEvent dmcRfidEvent,
                                        OldmanBedRoomBuildingVo obrvo) {

        Long rfidReadGroupId = rfidReaderGroupDto.getId();

        // 根据门禁组Id查询报警灯信息
        AlarmLightVo alarmLightVo = dmcAlarmLightLocationService.selectOneByRfidReadGroupId(rfidReadGroupId);

        int number = -1;
        // 判断当前门禁读卡器是门禁一还是门禁二
        for (RfidReaderDto rrd : rfidReaderGroupDto.getRfidReaderGroupList()) {
            if (rrd.getDeviceId().equals(dmcRfidReaderVo.getId())) {
                number = rrd.getNumber();
                break;
            }
        }

        // 查询老人所在班组
        NursingGroupOldmanVo nursingGroupOldmanVo = omcRpcService
                .queryNursingGroupOldmanByOldmanId(dmcRfidLabelVo.getOldmanId().intValue());

        if (nursingGroupOldmanVo == null || nursingGroupOldmanVo.getNursingGroupId() == null) {
            throw new OmcBizException(ErrorCodeEnum.DMC10066004);
        }

        // 门禁老人记录
        DmcRfidEventOldman dmcRfidEventOldman = new DmcRfidEventOldman();
        dmcRfidEventOldman.setId(dmcRfidEvent.getId());
        dmcRfidEventOldman.setGroupId(dmcRfidLabelVo.getGroupId());
        dmcRfidEventOldman.setLocation(dmcRfidReaderVo.getLocation());
        dmcRfidEventOldman.setNumber(number);
        dmcRfidEventOldman.setOldmanId(dmcRfidLabelVo.getOldmanId().intValue());
        dmcRfidEventOldman.setOldmanName(dmcRfidLabelVo.getOldmanName());
        dmcRfidEventOldman.setNursingGroupId(nursingGroupOldmanVo.getNursingGroupId());

        String message;
        switch (number) {
            case 0 :
                // 插入门禁老人记录
                message = String.format("%s老人在%s经过门禁一,可能需要外出,是否允许外出?",
                        dmcRfidLabelVo.getOldmanName(), DateUtil.dateToString(new Date()));
                dmcRfidEventOldman.setMessage(message);
                dmcRfidEventOldmanService.save(dmcRfidEventOldman);

                DmcRfidEventOldmanVo dmcRfidEventOldmanVo = new DmcRfidEventOldmanVo();
                BeanUtils.copyProperties(dmcRfidEvent, dmcRfidEventOldmanVo);
                BeanUtils.copyProperties(dmcRfidEventOldman, dmcRfidEventOldmanVo);
                JSONObject jsonObject = JSONObject.fromObject(dmcRfidEventOldmanVo);

                // 推送外出通知给护工组
                List<String> tagList = new ArrayList<String>();
                tagList.add("nursing_" + dmcRfidLabelVo.getGroupId());

                jPushService.sendOldmanOutRecordMsg(tagList, message, jsonObject);
                break;
            case 1 :
                // 查询经过门禁一
                DmcRfidEventOldmanVo first = dmcRfidEventOldmanService.selectFirstRfidEvent(dmcRfidReaderVo, dmcRfidLabelVo);
                if (first == null) {    // 判断老人是否经过门禁一
                    // 未经过门禁一 暂不做任何处理
                    log.error("未经过门禁一, 经过门禁二");
                } else {
                    // 经过门禁一
                    DmcRfidEventOldman update = new DmcRfidEventOldman();
                    update.setId(first.getId());
                    update.setMatchStat(1);
                    dmcRfidEventOldmanService.update(update);

                    dmcRfidEventOldman.setMatchStat(1);
                    dmcRfidEventOldman.setPid(first.getId());

                    if (first.getDealStat().equals(1)) { // 判断是否处理
                        // 已经处理
                        if (first.getDealResult().equals(1)) { // 判断是否允许
                            // 允许外出
                            message = String.format("%s,被%s护工允许外出的%s老人经过第二个门禁外出",
                                    DateUtil.dateToString(new Date()), first.getUserName(), first.getOldmanName());
                            dmcRfidEventOldman.setMessage(message);
                            dmcRfidEventOldman.setDealTime(first.getDealTime());
                            dmcRfidEventOldman.setDealStat(1);
                            dmcRfidEventOldman.setDealResult(1);

                            dmcRfidEventOldman.setUserId(first.getUserId());
                            dmcRfidEventOldman.setUserName(first.getUserName());
                            dmcRfidEventOldmanService.save(dmcRfidEventOldman);

                            // 设置门禁组对应的灯亮灭
                            // 暂不做处理
                            // 改动了报警灯的控制流程 给网络继电器一个闭合后 再给一个松开
                        } else {
                            // 不允许外出

                            // 限制老人外出 发送报警
                            rfidReaderGroupOldmanProccess(dmcRfidReaderVo, dmcRfidLabelVo, dmcRfidEventOldman, alarmLightVo, obrvo);
                        }
                    } else{
                        // 未处理

                        // 限制老人外出 发送报警
                        rfidReaderGroupOldmanProccess(dmcRfidReaderVo, dmcRfidLabelVo, dmcRfidEventOldman, alarmLightVo, obrvo);
                    }
                }

                break;
            default:
                throw new DmcBizException(ErrorCodeEnum.DMC10065005);
        }
    }

    /**
     * process rfid reader group oldman alert
     *
     * @param dmcRfidReaderVo       the dmc rfid reader vo
     * @param dmcRfidLabelVo        the dmc rfid label vo
     * @param dmcRfidEventOldman    the dmc rfid event oldman
     */
    public void rfidReaderGroupOldmanProccess(DmcRfidReaderVo dmcRfidReaderVo,
                                              DmcRfidLabelVo dmcRfidLabelVo,
                                              DmcRfidEventOldman dmcRfidEventOldman,
                                              AlarmLightVo alarmLightVo,
                                              OldmanBedRoomBuildingVo obrvo) {

        if (alarmLightVo == null || PublicUtil.isEmpty(alarmLightVo.getDeviceNo())) {
            throw new DmcBizException(ErrorCodeEnum.DMC10065006);
        }

        log.info("====> chisj alarm light no = [{}]", alarmLightVo.getDeviceNo());
        try {
            RelayCmdStachEntity relayCmdStachEntity = new RelayCmdStachEntity();
            relayCmdStachEntity.setDeviceNo(alarmLightVo.getDeviceNo());
            relayCmdStachEntity.setN(1);
            relayCmdStachEntity.setSta(1);
            relayMessageHandler.setStach(relayCmdStachEntity);

            Thread.sleep(1000l);

            relayCmdStachEntity.setSta(0);
            relayMessageHandler.setStach(relayCmdStachEntity);
        } catch (Exception e) {
            e.printStackTrace();
        }

        DmcDeviceAlert dmcDeviceAlert = new DmcDeviceAlert();
        alarmLightVo.setLocation(dmcRfidReaderVo.getLocation());
        Integer result = dmcDeviceAlertService.rfidReaderGroupAlertMsg(alarmLightVo,
                dmcRfidLabelVo, dmcDeviceAlert, obrvo);
        if (result > 0) {
            dmcDeviceAlertService.sendDeviceAlertMsg(dmcDeviceAlert, obrvo);
            dmcDeviceAlertService.sendLifeMsg(dmcDeviceAlert, obrvo, LifeConstant.YES_SOUND);
        }

        dmcRfidEventOldman.setMessage(dmcDeviceAlert.getAlertInfo());
        dmcRfidEventOldmanService.save(dmcRfidEventOldman);
    }

    /**
     * 下載孝心手环提醒语音文件
     */
    @RequestMapping(value = "/downloadDmcWatchAlarmClockVoiceDataById/{id}")
    public Wrapper queryDmcWatchAlarmClockVoiceDataById(@PathVariable Long id,
                                                        HttpServletResponse response) throws IOException {

        // 1.校验 闹钟Id
        Preconditions.checkArgument(id != null,
                cmnyMessageSource.getMessage("watch.alarm.clock.id.null", null));
        DmcWatchAlarmClock dmcWatchAlarmClockQuery = dmcWatchAlarmClockService.selectByKey(id);
        if (PublicUtil.isEmpty(dmcWatchAlarmClockQuery)) {
            throw new DmcBizException(ErrorCodeEnum.DMC100610019, id);
        }

        if (PublicUtil.isEmpty(dmcWatchAlarmClockQuery.getVoiceData())) {
            throw new DmcBizException(ErrorCodeEnum.DMC100610020, id);
        }

        byte[] data = dmcWatchAlarmClockQuery.getVoiceData();
        String fileName = dmcWatchAlarmClockQuery.getId().toString() + ".amr";
        response.setHeader("content-disposition", "attachment;filename=" + fileName);
        InputStream inStream = new ByteArrayInputStream(data);
        OutputStream os = response.getOutputStream();

        byte[] buff = new byte[1024];
        int len = -1;
        while ((len = inStream.read(buff)) > 0) {
            os.write(buff, 0, len);
        }
        os.flush();
        os.close();

        inStream.close();
//        fileName = URLEncoder.encode(fileName, "UTF-8");
//        response.reset();
//        response.setHeader("Content-Disposition", "attachment; filename=\"" + fileName + "\"");
//        response.addHeader("Content-Length", "" + data.length);
//        response.setContentType("application/octet-stream;charset=UTF-8");
//        OutputStream outputStream = new BufferedOutputStream(response.getOutputStream());
//        outputStream.write(data);
//        outputStream.flush();
//        outputStream.close();

        return WrapMapper.ok();
    }

    /**
     * 设备编号
     *
     * @param deviceNo  device no
     *
     * @return
     */
    @RequestMapping(value = "/cameraAuth")
    public Wrapper cameraAuth(@RequestParam("deviceNo") String deviceNo) {

        Preconditions.checkArgument(PublicUtil.isNotEmpty(deviceNo),
                cmnyMessageSource.getMessage("camera.no.null", null));

        // 获取设备信息
        String redisKey = RedisKeyUtil.getCsunCameraKey(deviceNo);
        CsunCameraData csunCameraData = (CsunCameraData) redisTemplate.opsForValue().get(redisKey);

        if (PublicUtil.isEmpty(csunCameraData)) {
            // 设备尚未绑定
            return WrapMapper.error("设备尚未绑定");
        }
        Long deviceId = csunCameraData.getDeviceId();

        // 获取流媒体服务器信息 (server1:port1,server2:port2)
        String stunServer = dmcServerService.queryStunServer();
        String turnServer = dmcServerService.queryTurnServer();
        String sipServer = dmcServerService.querySipServer();

        // 产生设备的使用的密码（用于relay server认证）
        RelayAuthDto relayAuthDto = new RelayAuthDto();
        relayAuthDto.setDeviceId(deviceId);
        relayAuthDto.setUsername(deviceNo);
        String password = dmcRelayAuthDeviceService.create(relayAuthDto);

        Map<String, Object> map = Maps.newHashMap();
        map.put("deviceId", deviceId);
        map.put("deviceNo", deviceNo);
        map.put("stunServer", stunServer);
        map.put("turnServer", turnServer);
        map.put("sipServer", sipServer);
        map.put("username", deviceNo);
        map.put("password", password);
        map.put("tcpServer", cmnyProperties.getNetty().getCamera().getHost()
                + ":" + cmnyProperties.getNetty().getCamera().getPort());
        map.put("rtmpServer", cmnyProperties.getNetty().getCamera().getRtmpUrl());
        map.put("queryVersion", cmnyProperties.getNetty().getCamera().getQueryVersion());
        map.put("downVersion", cmnyProperties.getNetty().getCamera().getDownVersion());
        map.put("webrtcHost", cmnyProperties.getNetty().getCamera().getWebrtcHost());

        // 根据摄像头编号查询webrtc客户端编号
        DmcCsunCameraWebRtc dmcCsunCameraWebRtc = dmcCsunCameraWebRtcService
                .selectByDeviceId(csunCameraData.getDeviceId());
        if (PublicUtil.isNotEmpty(dmcCsunCameraWebRtc)) {
            map.put("clientNo", dmcCsunCameraWebRtc.getClientNo());
        }

        return WrapMapper.ok(map);
    }

    @RequestMapping(value = "/cameraMsg")
    public Wrapper cameraMsg(@RequestBody Map<String, String> param) {

        if (PublicUtil.isEmpty(param)) {
            return WrapMapper.error("参数不能为空");
        }

        String msgType = param.get("msgType");
        if (PublicUtil.isEmpty(msgType)) {
            return WrapMapper.error("未识别的消息");
        }

        String deviceNo = param.get("deviceNo");
        if (PublicUtil.isEmpty(deviceNo)) {
            return WrapMapper.error("设备编号不能为空");
        }

        // 获取设备信息
        String redisKey = RedisKeyUtil.getCsunCameraKey(deviceNo);
        CsunCameraData csunCameraData = (CsunCameraData) redisTemplate.opsForValue().get(redisKey);

        if (PublicUtil.isEmpty(csunCameraData)) {
            // 设备尚未绑定
            return WrapMapper.error("设备尚未绑定");
        }

        OldmanBedRoomBuildingVo obrvo = new OldmanBedRoomBuildingVo();
        DmcDeviceAlert dmcDeviceAlert = new DmcDeviceAlert();
        switch (msgType) {
            case "fillMsg" :
                // 处理老人跌倒报警消息
                // 1.校验报警录像文件名(设备名+时间戳)
                String videoFileName = param.get("videoFileName");
                if (PublicUtil.isEmpty(videoFileName)) {
                    return WrapMapper.error("报警录像名不能为空");
                }
                // 2.报警消息
                Integer result = dmcDeviceAlertService.csunCameraAlertMsg(csunCameraData.getDeviceId(), dmcDeviceAlert, obrvo, CameraConstant.CSUN_CAMERA_FILL);
                if (result > 0) {
                    // 3.推送报警
                    dmcDeviceAlertService.sendDeviceAlertMsg(dmcDeviceAlert, obrvo);
                    dmcDeviceAlertService.sendLifeMsg(dmcDeviceAlert, obrvo, LifeConstant.YES_SOUND);
                }
                // 4.保存报警录像视频
                DmcCsunCameraAlertVideo dmcCsunCameraAlertVideo = new DmcCsunCameraAlertVideo();
                dmcCsunCameraAlertVideo.setAlertId(dmcDeviceAlert.getId());
                dmcCsunCameraAlertVideo.setDeviceId(dmcDeviceAlert.getDeviceId());
                dmcCsunCameraAlertVideo.setDeviceNo(dmcDeviceAlert.getDeviceNo());
                dmcCsunCameraAlertVideo.setVideoFileName(videoFileName);
                dmcCsunCameraAlertVideoService.save(dmcCsunCameraAlertVideo);

                break;
        }

        return WrapMapper.ok(dmcDeviceAlert.getId());
    }

    @PostMapping(value = "/cameraPicture")
    public Wrapper cameraPicture(@RequestBody CsunCameraPictureAckMsg csunCameraPictureAckMsg) {

        String redisKey = RedisKeyUtil.getCsunCameraKey(csunCameraPictureAckMsg.getSn());
        CsunCameraData csunCameraData = (CsunCameraData) redisTemplate.opsForValue().get(redisKey);

        if (PublicUtil.isEmpty(csunCameraData)) {
            // 设备尚未绑定
            return WrapMapper.error("设备尚未绑定");
        }

        redisKey = RedisKeyUtil.getCsunCameraTask(csunCameraPictureAckMsg.getTaskId());
        log.info("====> chisj redis key = {}", redisKey);
        redisTemplate.opsForValue().set(redisKey, csunCameraPictureAckMsg, 1, TimeUnit.MINUTES);

        DmcCsunCameraPicture dmcCsunCameraPicture = new DmcCsunCameraPicture();
        dmcCsunCameraPicture.setDeviceId(csunCameraData.getDeviceId());
        dmcCsunCameraPicture.setDeviceNo(csunCameraData.getDeviceNo());
        dmcCsunCameraPicture.setTaskId(csunCameraPictureAckMsg.getTaskId());
        dmcCsunCameraPicture.setFormat(csunCameraPictureAckMsg.getFormat());
        dmcCsunCameraPicture.setPicture(getImageByte(csunCameraPictureAckMsg.getPicture()));
        // dmcCsunCameraPicture.setPicture(csunCameraPictureAckMsg.getPicture().getBytes());

        // 确认拍照指令,避免重发
        // cameraMessageHandler.dealCmdConfirm(dmcCsunCameraPicture.getTaskId(), null);

        dmcCsunCameraPictureService.save(dmcCsunCameraPicture);

        return WrapMapper.ok();
    }

    @RequestMapping(consumes = "multipart/form-data", value = "/uploadCsunVersionFile", method = RequestMethod.POST)
    public Wrapper uploadVersion(HttpServletRequest request) {

        Integer type = Integer.parseInt(request.getParameter("fileType"));
        String version = request.getParameter("fileVersion");

        MultipartHttpServletRequest multipartRequest = (MultipartHttpServletRequest) request;
        List<MultipartFile> fileList = multipartRequest.getFiles("file");
        if (fileList.isEmpty()) {
            return WrapMapper.error("文件不能为空");
        }

        byte[] buffer = null;
        String fileName = "";
        try {
            for (MultipartFile multipartFile : fileList) {
                fileName = multipartFile.getOriginalFilename();
                if (PublicUtil.isEmpty(fileName)) {
                    continue;
                }
                buffer = multipartFile.getBytes();
                break;
            }
        } catch (Exception e) {
            e.printStackTrace();
        }

        /* 将当前上下文初始化给  CommonsMutipartResolver （多部分解析器）*/
//        CommonsMultipartResolver multipartResolver=new CommonsMultipartResolver(
//                request.getSession().getServletContext());
//
//        byte[] buffer = null;
//        /* 检查form中是否有enctype="multipart/form-data" */
//        if(multipartResolver.isMultipart(request)) {
//            /* 将request变成多部分request */
//            MultipartHttpServletRequest multiRequest = (MultipartHttpServletRequest) request;
//
//            /* 获取multiRequest 中所有的文件名*/
//            Iterator iter = multiRequest.getFileNames();
//            while(iter.hasNext()) {
//                MultipartFile file = multiRequest.getFile(iter.next().toString());
//                try{
//                    //将文件转换成byte[]
//                    buffer = file.getBytes();
//                }catch (Exception e ) {
//                    throw new RuntimeException();
//                }
//                break;
//            }
//        }

        DmcCsunVersionFile dmcCsunVersionFile = new DmcCsunVersionFile();
        dmcCsunVersionFile.setFileType(type);
        dmcCsunVersionFile.setFileVersion(version);
        dmcCsunVersionFile.setFileData(buffer);
        dmcCsunVersionFile.setLength(buffer.length);
        dmcCsunVersionFile.setFileName(fileName);
        dmcCsunVersionFile.setMd5(MD5Util.getMD5String(buffer));
        //dmcCsunVersionFile.setBase64Md5(MD5Util.getMD5String(Base64.encodeBase64String(buffer)));

        dmcCsunVersionFileService.save(dmcCsunVersionFile);

        return WrapMapper.ok();
    }

    @RequestMapping(consumes = "multipart/form-data", value = "/uploadCsunSleepFile", method = RequestMethod.POST)
    public Wrapper uploadCsunSleepFile(HttpServletRequest request) {

        String deviceNo = request.getParameter("deviceNo");

        MultipartHttpServletRequest multipartRequest = (MultipartHttpServletRequest) request;
        List<MultipartFile> fileList = multipartRequest.getFiles("file");
        if (fileList.isEmpty()) {
            return WrapMapper.error("文件不能为空");
        }

        byte[] buffer = null;
        String fileName = "";
        try {
            for (MultipartFile multipartFile : fileList) {
                fileName = multipartFile.getOriginalFilename();
                if (PublicUtil.isEmpty(fileName)) {
                    continue;
                }
                buffer = multipartFile.getBytes();
                break;
            }
        } catch (Exception e) {
            e.printStackTrace();
        }

        DmcCsunSleepCollection dmcCsunSleepCollection = new DmcCsunSleepCollection();
        dmcCsunSleepCollection.setDeviceNo(deviceNo);
        dmcCsunSleepCollection.setFileData(buffer);
        dmcCsunSleepCollection.setFileName(fileName);

        dmcCsunSleepCollectionService.save(dmcCsunSleepCollection);

        return WrapMapper.ok();
    }

    /**
     *  查询版本信息
     *
     * @param dmcCsunVersionFile
     *
     * @return
     */
    @RequestMapping(value = "/queryCsunVersion")
    public Wrapper queryCsunVersion(DmcCsunVersionFile dmcCsunVersionFile) {

        DmcCsunVersionFile record = dmcCsunVersionFileService.queryCsunVersionFile(dmcCsunVersionFile);

        if (record == null) {
            return WrapMapper.error("尚未查询到版本信息");
        }

        //String md5 = MD5Util.getMD5String(record.getFileData());

        CsunVersionVo csunVersionVo = new CsunVersionVo();
        csunVersionVo.setFileType(record.getFileType());
        csunVersionVo.setFileVersion(record.getFileVersion());
        csunVersionVo.setLength(record.getLength());
        csunVersionVo.setMd5(record.getMd5());

        return WrapMapper.ok(csunVersionVo);
    }

    @RequestMapping(value = "/pictureShow", produces = {"text/html; charset=UTF-8"})
    public void pictureShow(String deviceNo, HttpServletResponse response) throws IOException {

        boolean flag = true;
        // OutputStream os = response.getOutputStream();  //创建输出流

        DmcCsunCameraPicture dmcCsunCameraPicture = dmcCsunCameraPictureService.selectByDeviceNo(deviceNo);

        try {
            if (dmcCsunCameraPicture != null) {
                flag = false;
                ByteArrayInputStream byteArrayInputStream = new ByteArrayInputStream(dmcCsunCameraPicture.getPicture());
                BufferedImage bufferedImage = ImageIO.read(byteArrayInputStream);
                if (bufferedImage != null) {
                    ImageIO.write(bufferedImage, "jpg", response.getOutputStream());
                    //response.setContentType("image/jpg");
                } else {
                    flag = true;
                }
            }

            if (flag) {
                ClassPathResource cpr = new ClassPathResource("static/DefaultCamera.png");
                BufferedImage bufferedImage = ImageIO.read(cpr.getInputStream());
                ImageIO.write(bufferedImage, "png", response.getOutputStream());
                // response.setContentType("image/png");
            }

            response.setContentType("octet-stream");
            response.flushBuffer();
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    @RequestMapping(value = "/image")
    public void image(HttpServletRequest request, HttpServletResponse response) {
        System.out.println("");
        try {

            String picture = "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SGf/2Q==U1weOKM0LTsUhiZNA4pTxSdaAHA0nAPFL0FMzmgB9FIDRSGf/9k=WpCGc7m6VlXVqUHmryO49Ks6bejIhkPX7p/pS8h2vqa4PHFLn86FpcUDEyaBSnik60APBpvAJpRwKbnJoAfRTQcUUhn/2Q==jbedDvX76/qKklkCnjrVdrhnO1atRJcuxWsL0wZjb7h6e1akO523N0rJurVkHmjkd6tabejIhkPX7p/pR5Ba+prA8cUufWkWnYpDEzSijpSdaAHg03ABOKUcU3OaBj6KQGikB//ZQA8GkwAeKBwKaTmgY+imqaKQz//Z";

            if (StringUtils.isEmpty(picture)) {
                System.out.println("picture is null");
            } else {
                ByteArrayInputStream byteArrayInputStream = null;
                try {
                    BASE64Decoder decoder = new BASE64Decoder();
                    byte[] byteArray = decoder.decodeBuffer(picture);
                    byteArrayInputStream = new ByteArrayInputStream(byteArray);
                    BufferedImage bufferedImage = ImageIO.read(byteArrayInputStream);

                    org.springframework.core.io.Resource resource = new ClassPathResource("static/DefaultCamera.png");
                    InputStream is = resource.getInputStream();
                    //BufferedImage bufferedImage = ImageIO.read(is);
//                    if (bufferedImage == null) {
//                        log.error("====> 拍照失败...");
//                        return false;
//                    }

//                    File outputfile  = new File("G:/lu-1.jpg");
//                    ImageIO.write(bufferedImage,"jpg",outputfile);
//
//                    String image = imageToBase64("G:/lu-1.jpg");
//
//
//                    log.info("picture = {}", picture);
//                    log.info("image = {}", image);
                    ImageIO.write(bufferedImage, "jpg", response.getOutputStream());
                    response.setContentType("image/jpg");
                    response.flushBuffer();
                } finally {
                    if (byteArrayInputStream != null) {
                        byteArrayInputStream.close();
                    }
                }
            }

//            File file=File.createTempFile("qrcode"+System.currentTimeMillis(), ".png");
//            ImageIO.write(bufferedImage, "png", file);


//            ImageIO.write(bufferedImage, "png", response.getOutputStream());
//
//            response.setContentType("image/png");
//            response.flushBuffer();

        } catch (Exception e) {
            e.printStackTrace();
//            LOG.error("transform image stream error",e);
        }

    }

    @RequestMapping(value = "/downPacketCsunVersionFile")
    public Wrapper downPacketCsunVersionFile(HttpServletRequest request, HttpServletResponse response,
                                             PacketVersionDto packetVersionDto) throws IOException {

        DmcCsunVersionFile record = new DmcCsunVersionFile();
        record.setFileVersion(packetVersionDto.getFileVersion());
        record.setFileType(packetVersionDto.getFileType());

        record = dmcCsunVersionFileService.queryCsunVersionFile(record);
        Preconditions.checkArgument(record != null, cmnyMessageSource
                .getMessage("down.csun.version.file.null", null));

        /**
         * @author  chisj
         * @date    2021-01-11
         * @desc    新增本地文件分包
         */
        byte[] buffer = record.getFileData();
        if (record.getWay().equals(2)) {
            File file = new File(record.getPath());
            FileInputStream fis = new FileInputStream(file);
            ByteArrayOutputStream bos = new ByteArrayOutputStream();
            byte[] b = new byte[1024];
            int length;
            while ((length = fis.read(b)) != -1) {
                bos.write(b, 0, length);
            }
            fis.close();
            bos.close();
            buffer = bos.toByteArray();
        }

        Integer packIndex = packetVersionDto.getPackIndex();
        Integer packLength = packetVersionDto.getPackLength();
        Integer packSize = record.getLength();
        Integer packCount = packSize % packLength == 0
                ? packSize / packLength
                : packSize / packLength + 1;
        Integer newPackLength = packLength;
        if (packIndex == packCount) {
            newPackLength = packSize % packLength == 0
                    ? packLength : packSize % packLength;
        }

        byte[] data = MD5Util.subBytes(buffer,
                (packIndex -1) *  packLength, newPackLength);
        String dateStr64 = Base64.encodeBase64String(data);
        String md5 = MD5Util.getMD5String(data);

        CsunVersionPackVo csunVersionPackVo = new CsunVersionPackVo();
        csunVersionPackVo.setBase64Length(dateStr64.length());
        csunVersionPackVo.setFileVersion(record.getFileVersion());
        csunVersionPackVo.setFileType(record.getVersion());
        csunVersionPackVo.setBase64Md5(md5);
        csunVersionPackVo.setMd5(record.getMd5());
        csunVersionPackVo.setPackData(dateStr64);
        csunVersionPackVo.setPackCount(packCount);
        csunVersionPackVo.setPackIndex(packIndex);
        csunVersionPackVo.setPackSize(packSize);
        csunVersionPackVo.setPackLength(newPackLength);

//        map.put("version", csunVersionFile.getVersion());
//        map.put("packCount", packCount);
//        map.put("packIndex", packIndex);
//        map.put("packSize", packSize);
//        map.put("packLength", newPackLength);
//        map.put("base64Length", dateStr64.length());
//        map.put("packData", dateStr64);
//        map.put("md5", md5);

        return WrapMapper.ok(csunVersionPackVo);
    }

    @RequestMapping(value = "/downCsunVersionFile")
    public void downCsunVersionFile(HttpServletRequest request, HttpServletResponse response,
                                    DmcCsunVersionFile dmcCsunVersionFile) throws IOException {

        DmcCsunVersionFile record = dmcCsunVersionFileService.queryCsunVersionFile(dmcCsunVersionFile);
        Preconditions.checkArgument(record != null, cmnyMessageSource
                .getMessage("down.csun.version.file.null", null));

        String filename = DateUtil.nowDateStr() + ".zip";

        File file = new File(record.getPath());

//        log.info("length = {}", record.getFileData().length);

        //设置响应流文件进行下载
        response.setHeader("Content-Disposition","attachment;filename="+filename);
        response.setHeader("Content-Type", "text/html;charset=utf-8");
        response.setHeader("Content-Length", record.getLength() + "");
        response.setHeader("Content-Language", "en");
        // response.setContentLength(record.getLength());
        ServletOutputStream sos = response.getOutputStream();
        FileInputStream fis = new FileInputStream(file);
        byte[] buffer = new byte[1024];
        int length;
        while ((length = fis.read(buffer)) > 0) {
            sos.write(buffer, 0 ,length);
        }
        sos.flush();
        sos.close();
    }



    @RequestMapping(consumes = "multipart/form-data", value = "/cameraFillVideo")
    public Wrapper cameraFillVideo(HttpServletRequest request) {

        MultipartHttpServletRequest multipartRequest = (MultipartHttpServletRequest) request;
        List<MultipartFile> fileList = multipartRequest.getFiles("video");
        if (fileList.isEmpty()) {
            return WrapMapper.error("文件不能为空");
        }

        OptUploadFileReqDto optUploadFileReqDto = new OptUploadFileReqDto();
        OptUploadFileByteInfoReqDto optUploadFileByteInfoReqDto = new OptUploadFileByteInfoReqDto();
        OptUploadFileRespDto optUploadFileRespDto = new OptUploadFileRespDto();
        try {
            for (MultipartFile multipartFile : fileList) {
                String fileName = multipartFile.getOriginalFilename();
                if (PublicUtil.isEmpty(fileName)) {
                    continue;
                }
                Preconditions.checkArgument(multipartFile.getSize() <= GlobalConstant.FILE_MAX_SIZE, "上传文件不能大于100M");
                optUploadFileByteInfoReqDto.setFileByteArray(multipartFile.getBytes());
                optUploadFileByteInfoReqDto.setFileName(fileName);

                optUploadFileReqDto.setUploadFileByteInfoReqDto(optUploadFileByteInfoReqDto);

                optUploadFileRespDto = opcRpcService.uploadFile(optUploadFileReqDto);

                break;
            }
        } catch (Exception e) {
            e.printStackTrace();
        }

        // 关联报警视频和报警Id
        Long alertId = Long.parseLong(request.getParameter("alertId"));

        return WrapMapper.ok();
    }

    public static String bytes2hex(byte[] bytes, int length) {
        StringBuilder sb = new StringBuilder();
        String tmp = null;
        for (int i = 0; i < length; i++) {
            // 将每个字节与0xFF进行与运算，然后转化为10进制，然后借助于Integer再转化为16进制
            tmp = Integer.toHexString(0xFF & bytes[i]);
            if (tmp.length() == 1) {
                tmp = "0" + tmp;
            }
            sb.append(tmp);
        }
        return sb.toString();
    }

    public static byte getCheckSum(byte[] buf, int len) {

        byte checkSum = 0 & 0xff;

        if (buf == null) {
            return checkSum;
        }

        for(int i=0; i < len; i++) {
            checkSum += buf[i];
        }

        return (byte)(~checkSum+1);
    }

    public String imageToBase64(String imgUrl) {

        InputStream in = null;

        byte data[] = null;

        try {
            in = new FileInputStream(imgUrl);
            data = new byte[in.available()];
            in.read();
            in.close();
        } catch (Exception e) {
            e.printStackTrace();
        }

        BASE64Encoder encoder = new BASE64Encoder();

        return encoder.encode(data);
    }

    public void generateImage(String imgStr, String imgUrl) {

        if (imgStr == null) // 图像数据为空
            return;
        BASE64Decoder decoder = new BASE64Decoder();
        try {
            // Base64解码
            byte[] bytes = decoder.decodeBuffer(imgStr);
            for (int i = 0; i < bytes.length; ++i) {
                if (bytes[i] < 0) { // 调整异常数据
                    bytes[i] += 256;
                }
            }
            // 生成图片
            OutputStream out = new FileOutputStream(imgUrl);
            out.write(bytes);
            out.flush();
            out.close();
            return;
        } catch (Exception e) {
            return;
        }
    }

    public byte[] getImageByte(String imgStr) {

        if (imgStr == null) // 图像数据为空
            return null;

        BASE64Decoder decoder = new BASE64Decoder();

        try {
            byte[] bytes = decoder.decodeBuffer(imgStr);

            for (int i = 0; i < bytes.length; ++i) {
                if (bytes[i] < 0) { // 调整异常数据
                    bytes[i] += 256;
                }
            }

            return bytes;
        } catch (Exception e) {
            e.printStackTrace();
        }

        return null;
    }

    @PostMapping(value = "/sleepUpload", consumes = "multipart/form-data")
    public Wrapper sleepUpload(HttpServletRequest request, String host, String deviceNo) throws IOException {

        MultipartHttpServletRequest multipartRequest = (MultipartHttpServletRequest) request;
        List<MultipartFile> fileList = multipartRequest.getFiles("file");

        MultiValueMap map = new LinkedMultiValueMap();

        if (PublicUtil.isNotEmpty(fileList)) {
            File f = File.createTempFile("tmp", null);
            fileList.get(0).transferTo(f);

            map.add("Payload", new FileSystemResource(f));

            f.deleteOnExit();
        }

        String url = String.format("%smattress%s", host, deviceNo);

        HttpHeaders headers = new HttpHeaders();
        headers.setContentType(MediaType.MULTIPART_FORM_DATA);


        HttpEntity httpEntity = new HttpEntity<>(map, headers); // 组装

        Object object = myRestTemplate.exchange(url, HttpMethod.POST, httpEntity, String.class);

        return WrapMapper.wrap(Wrapper.SUCCESS_CODE, cmnyMessageSource
                .getMessage("operation.success", null), object);
    }

    @RequestMapping(value = "/testUpload")
    public Wrapper testUpload(String month, HttpServletResponse response) {

        dmcGuoKangClientService.uploadSleepMonthReport(month);

        String filePathPrefix = "G:\\report\\";
        String filePathPrefixRedis = (String) redisTemplate.opsForValue().get(RedisKeyUtil.getCsunSleepReportFilePrefix());
        if (PublicUtil.isNotEmpty(filePathPrefix)) {
            filePathPrefix = filePathPrefixRedis;
        }
        String zipFilePath = filePathPrefix + "MS005-" + month + ".zip";
        File file = new File(zipFilePath);

        response.setHeader("content-disposition", "attachment;filename=" + file.getName());

        byte[] buffer = new byte[1024];
        try {

            FileInputStream fis = new FileInputStream(file);
            BufferedInputStream bis = new BufferedInputStream(fis);

            OutputStream os = response.getOutputStream();

            int i = bis.read(buffer);
            while (i != -1) {
                os.write(buffer, 0, i);
                i = bis.read(buffer);
            }
        } catch (Exception e) {
            e.printStackTrace();
        }

        return WrapMapper.wrap(Wrapper.SUCCESS_CODE,
                cmnyMessageSource.getMessage("operation.success", null));
    }

    @PostMapping(value = "/saveReportPath")
    public Wrapper saveReportPath(String path) {

        redisTemplate.opsForValue().set(RedisKeyUtil.getCsunSleepReportFilePrefix(), path);

        return WrapMapper.wrap(Wrapper.SUCCESS_CODE,
                cmnyMessageSource.getMessage("operation.success", null));
    }

    @PostMapping(value = "/getReportPath")
    public Wrapper getReportPath() {

        String path = (String) redisTemplate.opsForValue().get(RedisKeyUtil.getCsunSleepReportFilePrefix());

        return WrapMapper.wrap(Wrapper.SUCCESS_CODE,
                cmnyMessageSource.getMessage("operation.success", null), path);
    }

    @PostMapping(value = "/saveReportTime")
    public Wrapper saveReportTime(String time) {

        redisTemplate.opsForValue().set(RedisKeyUtil.getCsunSleepReportTime(), time);

        return WrapMapper.wrap(Wrapper.SUCCESS_CODE,
                cmnyMessageSource.getMessage("operation.success", null));
    }

    @PostMapping(value = "/getReportTime")
    public Wrapper getReportTime() {

        String time = (String) redisTemplate.opsForValue().get(RedisKeyUtil.getCsunSleepReportTime());

        return WrapMapper.wrap(Wrapper.SUCCESS_CODE,
                cmnyMessageSource.getMessage("operation.success", null), time);
    }
}
